package com.nowcoder.community.service;

import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.nowcoder.community.entity.DiscussPost;
import com.nowcoder.community.repository.DiscussPostMapper;
import com.nowcoder.community.utils.HostHolder;
import com.nowcoder.community.utils.RedisKeyUtil;
import com.nowcoder.community.utils.SensitiveWordFilter;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.util.HtmlUtils;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class DisccusPostService {
    @Autowired
    private DiscussPostMapper discussPostMapper;

    @Autowired
    private SensitiveWordFilter sensitiveWordFilter;

    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${cafeine.posts.max-size}")
    private int caffeinePostsMaxSize;

    @Value("${cafeine.posts.expire}")
    private int caffeinePostsExpire;

    // caffeine 核心接口：Cache
    // 常用子接口：LoadingCache, AsyncLoadingCache
    private LoadingCache<String, List<DiscussPost>> postsCache;
    private LoadingCache<Integer, Integer> postsRow;

    @PostConstruct
    public void init(){
        postsCache = Caffeine.newBuilder()
                .maximumSize(caffeinePostsMaxSize)
                .expireAfterWrite(caffeinePostsExpire, TimeUnit.SECONDS)
                .build(new CacheLoader<String, List<DiscussPost>>() {
                    @Nullable
                    @Override
                    public List<DiscussPost> load(@NonNull String key) throws Exception {
                        if (StringUtils.isBlank(key))
                            throw new IllegalArgumentException();

                        String[] params = key.split(":");
                        if (params == null || params.length != 2)
                            throw new IllegalArgumentException();

                        int offset = Integer.valueOf(params[0]);
                        int limit = Integer.valueOf(params[1]);
                        return discussPostMapper.findDiscussPost(0, offset, limit, true);
                    }
                });

        postsRow = Caffeine.newBuilder()
                .maximumSize(caffeinePostsMaxSize)
                .expireAfterWrite(caffeinePostsExpire, TimeUnit.SECONDS)
                .build(new CacheLoader<Integer, Integer>() {
                    @Nullable
                    @Override
                    public Integer load(@NonNull Integer userId) throws Exception {
                        return discussPostMapper.findDiscussPostRows(userId);
                    }
                });
    }

    public List<DiscussPost> findDiscussPost(int userId, int offset, int limit){
        return discussPostMapper.findDiscussPost(userId, offset, limit, false);
    }

    public List<DiscussPost> findDiscussPost(int userId, int offset, int limit, boolean orderByScore){
            if (userId == 0 && orderByScore){
                return postsCache.get(offset + ":" + limit);
            }
        return discussPostMapper.findDiscussPost(userId, offset, limit, orderByScore);
    }

    public int findDiscussPostRows(int userId){
        if (userId == 0){
            return postsRow.get(userId);
        }
        return discussPostMapper.findDiscussPostRows(userId);
    }

    public int addDiscussPost(DiscussPost post){
        if (post == null){
            throw new IllegalArgumentException("post 对象不能为 null");
        }

        // HTML转义
        post.setTitle(HtmlUtils.htmlEscape(post.getTitle()));
        post.setContent(HtmlUtils.htmlEscape(post.getContent()));
        // 敏感词过滤
        post.setTitle(sensitiveWordFilter.filter(post.getTitle()));
        post.setContent(sensitiveWordFilter.filter(post.getContent()));
        return discussPostMapper.insertDiscussPost(post);
    }

    public DiscussPost findDiscussPostById(int id){
        return discussPostMapper.selectDiscussPostById(id);
    }

    /**
     * 更新帖子类型
     * @param type 0-普通 1-置顶
     * */
    public int updateType(int id, int type){
        return discussPostMapper.updateType(id,type);
    }

    /**
     * 更新状态
     * @param status 0-正常 1-精华 2-拉黑
     * */
    public int updateStatus(int id, int status){
        return discussPostMapper.updateStatus(id, status);
    }

    /**
     * 更新帖子分数
     * */
    public int updateScore(int id, double score){
        return discussPostMapper.updateScore(id, score);
    }

    /**
     * 将帖子id 加入 redis 集合，已定时更新帖子分数
     * */
    public void refreshScore(int id){
        redisTemplate.opsForSet().add(RedisKeyUtil.getPostScoreUpdateRedisKey() , id);
    }
}
